package ru.ifmo.tanya.core.calls;

import ru.ifmo.tanya.core.users.User;
import ru.ifmo.tanya.core.users.UserState;
import ru.ifmo.tanya.keepers.User2CallMapKeeper;
import ru.ifmo.tanya.keepers.UserStateKeeper;
import ru.ifmo.tanya.keepers.UserStatusKeeper;

import java.util.Date;
import java.util.List;


public class Dispatcher {

    private final CallManager callManager = new CallManager();
    private final UserStatusKeeper userStatusKeeper = new UserStatusKeeper();
    private final UserStateKeeper userStateKeeper = new UserStateKeeper();
    private final User2CallMapKeeper user2CallMapKeeper = new User2CallMapKeeper();

    private static final Long maxTimeWaitingUserMillis = 1000 * 30L; // 30 sec

    public void startMonitoring() {
        while (true) {
            List<Call> callsHolding = callManager.getCallsHolding();
            for (Call call : callsHolding) {
                List<User> availableUsers = userStatusKeeper.getActiveUsersByGroup(call.getHuntGroup());
                if (!availableUsers.isEmpty()) {

                    Long holdTimeForCall = user2CallMapKeeper.getHoldTimeForCall(call);
                    if (holdTimeForCall > 0) {
                        if (holdTimeForCall < maxTimeWaitingUserMillis) {
                            continue;
                        } else {
                            User userToAnswerCall = user2CallMapKeeper.getUserToAnswerCall(call);
                            user2CallMapKeeper.removeHoldingCallForUser(userToAnswerCall);
                            userStateKeeper.updateState(userToAnswerCall, UserState.AVAILABLE);
                        }
                    }

                    User user = selectUserToAnswer(availableUsers);
                    user2CallMapKeeper.routeCallToUser(call, user);
                    userStateKeeper.updateState(user, UserState.INCOMING_CALL);
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private User selectUserToAnswer(List<User> candidates) {
        User result = null;
        long freeTime = 0;
        long maxFreeTime = 0;
        for (final User user : candidates) {
            Call latestCall = callManager.getLatestCompletedCallByUser(user);
            if (latestCall == null) {
                return user;
            }
            freeTime = new Date().getTime() - latestCall.getCreationTime().getTime();
            if (result == null) {
                result = user;
                maxFreeTime = freeTime;
                continue;
            }
            if (freeTime > maxFreeTime) {
                maxFreeTime = freeTime;
                result = user;
            }
        }
        return result;
    }
}
